package com.mayflygeek.mayflyask.framework.orm.impl;

import static com.google.common.base.MoreObjects.firstNonNull;
import static com.google.common.base.Preconditions.checkNotNull;

import java.io.Serializable;
import java.util.Arrays;
import java.util.List;

import javax.inject.Inject;

import org.springframework.data.domain.Page;
import org.springframework.transaction.annotation.Transactional;

import com.mayflygeek.mayflyask.framework.orm.BaseDao;
import com.mayflygeek.mayflyask.framework.orm.Hibernatify;
import com.mayflygeek.mayflyask.framework.orm.Query;
import com.mayflygeek.mayflyask.framework.util.Generics;

/**
 * @author 虫虫
 * @team 蜉蝣极客
 * @link www.mayflygeek.com
 * @Emial chongchong@mayflygeek.com
 * 
 */
@Transactional
public class BaseDaoImpl<T, ID extends Serializable> implements BaseDao<T, ID>{
	private static final String PROPERTY_NAME = "name";
	private Class<T> _persistentClass;
	private Hibernatify hibernatify;
	
	public BaseDaoImpl() {
		
	}
	
	public BaseDaoImpl(Hibernatify hibernatify, Class<T> persistentClass) {
		this.hibernatify = hibernatify;
		this._persistentClass = checkNotNull(persistentClass);
	}
	
	@Inject	
	public void setHibernatify(Hibernatify hibernatify) {
		this.hibernatify = hibernatify;
	}

	@Transactional(readOnly = true)
	@Override
	public T get(ID id) {
		return hibernatify.get(getEntityClass(), id);
	}

	@Transactional(readOnly = true)
	@Override
	public T getOrElse(ID id, T that) {
		final T result = find(id);
		return firstNonNull(result, that);
	}

	@Transactional
	@Override
	public T save(T entity) {
		return hibernatify.put(entity);
	}

	@Transactional
	@SuppressWarnings("unchecked")
	@Override
	public List<T> save(T entity, T... rest) {
		return hibernatify.put(entity, rest);
	}

	@Transactional
	@Override
	public List<T> save(T[] entities) {
		return hibernatify.put(Arrays.asList(entities));
	}

	@Transactional
	@Override
	public T update(T entity) {
		return hibernatify.put(entity);
	}

	@SuppressWarnings("unchecked")
	@Transactional
	@Override
	public List<T> update(T entity, T... rest) {
		return hibernatify.put(entity, rest);
	}

	@Transactional
	@Override
	public List<T> update(T[] entities) {
		return hibernatify.put(Arrays.asList(entities));
	}

	@Transactional
	@Override
	public void delete(T entity) {
		hibernatify.delete(entity);
	}

	@Transactional
	@SuppressWarnings("unchecked")
	@Override
	public void delete(T entity, T... rest) {
		hibernatify.delete(entity, rest);
		
	}

	@Transactional
	@Override
	public void delete(T[] entities) {
		hibernatify.delete(Arrays.asList(entities));
		
	}

	@Transactional
	@Override
	public void deleteById(ID id) {
		hibernatify.delete(getEntityClass(), id);
		
	}

	@Transactional
	@SuppressWarnings("unchecked")
	@Override
	public void deleteById(ID id, ID... rest) {
		hibernatify.delete(getEntityClass(), id , rest);
		
	}

	@Transactional
	@Override
	public void deleteById(ID[] ids) {
		hibernatify.delete(getEntityClass(), Arrays.asList(ids));
		
	}

	@Transactional(readOnly = true)
	@Override
	public int count() {
		return hibernatify.count(getEntityClass());
	}

	@Transactional(readOnly = true)
	@Override
	public List<T> findAll() {
		return hibernatify.find(getEntityClass());
	}

	@Transactional(readOnly = true)
	@Override
	public Page<T> findPage() {
		return query().page(1, Integer.MAX_VALUE).page();
	}

	@Transactional(readOnly = true)
	@Override
	public T find(ID id) {
		return hibernatify.find(getEntityClass(), id);
	}

	@Transactional(readOnly = true)
	@Override
	public List<T> findByProperty(String name, Object value) {
		return query().filterEqual(name, value).list();
	}

	@Transactional(readOnly = true)
	@Override
	public T findUniqueByProperty(String name, Object value) {
		return query().filterEqual(name, value).unique();
	}

	@Transactional(readOnly = true)
	@Override
	public List<T> findByName(Object value) {
		return findByProperty(PROPERTY_NAME, value);
	}

	@Transactional(readOnly = true)
	@Override
	public T findUniqueByName(Object value) {
		return findUniqueByProperty(PROPERTY_NAME, value);
	}

	@Transactional(readOnly = true)
	@Override
	public Query<T, T> query() {
		return new QueryImpl<T, T>(this);
	}

	@Transactional(readOnly = true)
	@Override
	public <RT> Query<T, RT> query(Class<T> resultClass) {
		return new QueryImpl<T, RT>(this,resultClass);
	}

	@Transactional(readOnly = true)
	@Override
	public <RT> RT unique(Query<T, RT> query) {
		return hibernatify.unique(query);
	}

	@Transactional(readOnly = true)
	@Override
	public <RT> List<RT> list(Query<T, RT> query) {
		return hibernatify.list(query);
	}

	@Transactional(readOnly = true)
	@Override
	public <RT> Page<RT> page(Query<T, RT> query) {
		return hibernatify.page(query);
	}

	@Transactional(readOnly = true)
	@Override
	public <RT> int count(Query<T, RT> query) {
		return hibernatify.count(query);
	}

	@SuppressWarnings("unchecked")
	@Override
	public Class<T> getEntityClass() {
		if (_persistentClass == null) {
			try {
				_persistentClass = (Class<T>) Generics.getTypeParameterClass(this.getClass());
			} catch (Exception e) {
				throw new RuntimeException("无法获取实体类型", e);
			}
		}
		return checkNotNull(_persistentClass, "无法获取实体类型");
	}
	
}
